#!/usr/bin/env python

import re
import constants
import serviceCommandParser
import os

"""
   This needs quite a bit of work here to implement EXACTLY
   how MXit want it. For example, it mustn't parse anything
   inside the $s for highlighted text... Grr. Also, it needs
   to support escaping of markup. O.o I have some ideas for that tho
   but they aren't good ones <-- I can't remember what those ideas
                                 are now anyway...
"""

### Message Parsing classes for BlendIT ###

MARKUP = 0;
SERVICE = 1;

class Parser:
   handlers = [];
  
   def addParser(self,parser):
      self.handlers.append(parser);

   def defaultParser(self,data):
      #print 'default';
   	# unescape escaped stuff
      data = data.replace("\\*","*");
      data = data.replace("\\/","/");
      data = data.replace("\\_","_");
      data = data.replace("\\.",".");

      # replace \n with <br/>
      return data.replace("\n","<br/>");

   def sanitiseParser(self,message):
      # Also has to replace '<', '>' with  &lt; and &gt;
      message = message.replace("&","&amp;");
      message = message.replace("<","&lt;");
      message = message.replace(">","&gt;");
      return message;

   # Markup: bold, italics, underline, big, small
   # Patterns:
   # Bold:
   #    *WORD(S)*
   # Italic:
   #    /WORD(S)/
   # Underline:
   #    _WORD(S)_
   # Bigger Text:
   #   .+WORD
   # Smaller Text:
   #   .-WORD
   # Highlight:
   #   $WORD(S)$
   def replaceMarkup(self,matchobj):
      res = matchobj.groupdict();
      keys = res.keys();
      
      #pre = '';
      #post = '';
      
      #print res;
             
      for i in range(0,len(keys)):
         if res[keys[i]] != None:
            data = res[keys[i]];
            # Escaped. Do nothing
            if data[0] == "\\":
               return data;

            if keys[i] == "bold":
               # Bold stuff
               data = data.replace("\\*","\0");
               data = data.replace("*","%s");
               data = data % ('<span style="font-weight: bold">',"</span>");
               data = data.replace("\0","*");
            elif keys[i] == "italic":
               # Italic it
               data = data.replace("\\/","\0");
               data = data.replace("/","%s");
               data = data % ('<span style="font-style: italic">',"</span>");
               data = data.replace("\0","\\/");
            elif keys[i] == "underline":
               # Underline this
               data = data.replace("\\_","\0");
               data = data.replace("_","%s");
               data = data % ('<span style="text-decoration: underline">',"</span>");
               data = data.replace("\0","\\_");
            elif keys[i] == "highlight":
               # Escape all markup in the highlight
               data = data.replace("*","\\*");
               data = data.replace("/","\\/");
               data = data.replace("_","\\_");
               data = data.replace(".","\\.");
               data = data.replace("\\$","\0");
               m = data[1:-1].replace("$","").replace(":","%3a");
               data = data.replace("$","%s");
               data = data % ('<a href="blendit:\/\/sendmessage:%s">' % m,"</a>");
               data = data.replace("\0","\\$");
            elif keys[i] == "bigger":
               data = data.replace(".+","%s");
               post = data[-1];
               if post == " " or post == "":
                  data = data[:-1] + "%s" + post;
               else:
                  data = data + "%s";

               data = data % ('<span style="font-size: large">',"</span>");
               #print data;
            elif keys[i] == "smaller":
               data = data.replace(".-","%s");
               post = data[-1];
               data = data[:-1] + "%s" + post;
               data = data % ('<span style="font-size: small">',"</span>");
            
            # Recursive! YAY . . . .
            return self.markupParser(data); 
            
   def markupParser(self,message):
      boldPattern = r"(?P<bold>(^|[^\\])\*.+?(?<!\\)\*)";
      italicPattern = r"(?P<italic>(^|[^\\])/.+?(?<!\\)/)";
      underlinePattern = r"(?P<underline>(^|[^\\])_.+?(?<!\\)_)";
      highlightPattern = r"(?P<highlight>(^|[^\\])\$.+?\$(?<!\\))";
      biggerPattern = r"(?P<bigger>(^|[^\\])\.\+.+?(\s|$))"; 
      smallerPattern = r"(?P<smaller>(^|[^\\])\.\-.+?(\s|$))";     
      pattern = re.compile(highlightPattern + "|" + boldPattern + "|" + italicPattern + "|" + underlinePattern + "|" + biggerPattern + "|" + smallerPattern,re.MULTILINE);
      message = pattern.sub(self.replaceMarkup,message);

      return message;


   def replaceURL(self,matchobj):
      res = matchobj.groupdict();
      keys = res.keys();
      for i in range(0,len(keys)):
         if res[keys[i]] != None:
            data = res[keys[i]];

            # Escape markup
            data = data.replace("*","\\*");
            data = data.replace("/","\\/");
            data = data.replace("_","\\_");
            data = data.replace(".+","\\.+");
            data = data.replace("-+","\\-+");
            data = data.replace("$","\\$");

            if keys[i] == "url":
               #data is the url. First strip the whitespace:
               link = data.strip();
               url = link;
               if url.lower().startswith("http") == False or url.lower().startswith("ftp") == True:
                  link = "http:\/\/" + link;
               data = '<a href="%s">%s</a>';

               return data % (link,url);
            elif keys[i] == "mail":
               url = data.strip();
               data = '<a href="mailto:%s">%s</a>';
               return data % (url,url);

            elif keys[i] == "blend":
               return data;

   def urlParser(self,message):
      # Line below attribution: http://geekswithblogs.net/casualjim/archive/2005/12/01/61722.aspx
      urlPattern = r"(?P<url>((ht|f)tp(s?)\:\/\/|~/|/)([\w]+:\w+@)?([a-zA-Z]{1}([\w\-]+\.)+([\w]{2,5}))(:[\d]{1,5})?((/?\w+/)+|/?)(\w+\.[\w]{3,4})?((\?\w+=\w+)?(&\w+=\w+)*))";

      # Line below attribution: http://www.osix.net/modules/article/?id=586  
      regex = r"([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)";
      mailPattern = r"(?P<mail>" + regex + ")";
      
      blendItPattern = r"(?P<blend>\<a href=\"blendit\://(.+?)\"\>)";
      
      pattern = re.compile(urlPattern + "|" + mailPattern + "|" + blendItPattern,re.MULTILINE);
      
      message = pattern.sub(self.replaceURL,message);
      return message;

   def replaceColour(self,matchobj):
      res = matchobj.groupdict();
      keys = res.keys();
      for i in range(0,len(keys)):
         if res[keys[i]] != None:
            data = res[keys[i]];
            if keys[i] == 'colour':
               colour = data.split("#")[1][:6];
               data = data.replace("#" + colour,"%s").replace("#??????","%s");
               return data % ('<span style="color: #' + colour + '">', '</span>');

   def colourParser(self,message):
      #if 
      pattern = r"(?P<colour>#[0-9a-fA-F]{6}.*#\?\?\?\?\?\?)";
      pattern = re.compile(pattern);
      message = pattern.sub(self.replaceColour,message);

      # Entire message colour:
      pattern = r"^#([0-9a-fA-F]{6})(.*)$";
      match = re.search(pattern,message);
      
      if match:
         colour = str(match.group(1));
         msg = str(match.group(2));
         message = '<span style="color: #%s">%s</span>';
         message = message % (colour,msg);
      return message;


   def replaceEmoticon(self,matchobj):
      res = matchobj.groupdict();
      keys = res.keys();

      for i in range(0,len(keys)):
         if res[keys[i]] != None:
            data = res[keys[i]];

            #print "WE matched", data;

            if str(data) != "":
               key = int(keys[i][3:]);
               d = constants.C.emotes[key].image;
               a = constants.C.emotes[key].text;
               p = constants.C.emotes[key].pattern;
               
               """
               if data[0] == p[0]:
                  pre = "";
               else:
                  pre = data[0];
                  
               if data[-1] == p[-1]:
                  post = "";
               else:
                  post = data[-1];
               """
               
               #m = pre + '<img src="%s" alt="%s" />' % (d,a) + post;
               m = data.replace(p,'<img src="%s" alt="%s" />' % (os.path.abspath(d),p));
               

               # Escape markup
               m = m.replace("*","\\*");
               m = m.replace("/","\\/");
               m = m.replace("_","\\_");
               m = m.replace(".+","\\.+");
               m = m.replace("-+","\\-+");
               m = m.replace("$","\\$");

               return m;           
      
      return '';


   def emoticonParser(self,message):
      keys = constants.C.emotes;
      groups = "";
      for i in range(0,len(keys)):
         e = keys[i].pattern; # Emoticon Pattern
         # We have to escape some emoticon characters
         # that could be mistaken as part of a regex expression
         e = e.replace("(",r"\(")
         e = e.replace(")",r"\)")
         e = e.replace("*",r"\*")
         e = e.replace("$",r"\$")
         e = e.replace("{",r"\{")
         e = e.replace("}",r"\}")
         e = e.replace("|",r"\|")
         e = e.replace("?",r"\?")
         groups += r"(?P<grp" + str(i) + ">" + e + r")|";
      
      pattern = re.compile(groups[:-1],re.MULTILINE);
      return pattern.sub(self.replaceEmoticon,message);

   
   def parse(self,message,*params):
      for i in range(0,len(self.handlers)):
         message = self.handlers[i](message);
      return message;
      
   def __init__(self,blend):
      self.addParser(self.urlParser);
      self.addParser(self.emoticonParser);
      self.addParser(self.markupParser);
      self.addParser(self.colourParser);
      self.addParser(self.defaultParser);
      
      self.commandParse = serviceCommandParser.serviceCommandParser(blend);
